﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;

using BlueCMS.Core.Data;
using BlueCMS.Core.Data.Query.Clauses;
using BlueCMS.Core.Data.Query.Columns;
using BlueCMS.Core.Data.Query.Conditions;
using BlueCMS.Core.Data.Query.Tables;
using BlueCMS.Core.Providers;

namespace BlueCMS.Core.Data.Query.Generator
{
    public abstract partial class QueryGeneratorBase
    {
        public virtual string ParameterToken
        {
            get { throw new NotImplementedException(); }
        }

        public virtual string StartingQuoteToken
        {
            get { throw new NotImplementedException(); }
        }

        public virtual string EndingQuoteToken
        {
            get { throw new NotImplementedException(); }
        }

        protected virtual void GenerateConditionStatements(ConditionChain conditions, StringBuilder sb, Dictionary<string, DbParameter> parameters)
        {
            for (ConditionBase condition = conditions.Next; condition != null; condition = condition.Next)
            {
                if (condition is StartNode)
                {
                    sb.Append("(");
                }
                else if (condition is EndNode)
                {
                    sb.Append(")");
                }
                else if (condition is LogicNode)
                {
                    if (((LogicNode)condition).Type == LogicNodeType.And)
                    {
                        sb.Append(" AND ");
                    }
                    else
                    {
                        sb.Append(" OR ");
                    }
                }
                else if (condition is ConditionNode)
                {
                    GenerateCondition((ConditionNode)condition, sb);
                }
                else if (condition is ExistsNode)
                {
                    GenerateExists((ExistsNode)condition, sb);
                }
                else if (condition is SubSelectNode)
                {
                    GenerateSubSelect(((SubSelectNode)condition).Query, sb);
                }
                else if (condition is ParameterNode)
                {
                    GenerateParameter(((ParameterNode)condition).Value, sb, parameters);
                }
                else if (condition is ConstantNode)
                {
                    GenerateConstant(((ConstantNode)condition).Value, sb);
                }
                else if (condition is AggregateNode)
                {
                    GenerateAggregate(((AggregateNode)condition).Clause, sb);
                }
                else if (condition is ColumnNode)
                {
                    GenerateColumnName((string)((ColumnNode)condition).Name, sb);
                }
                else
                {
                    throw new QueryException("Unknown node type");
                }
            }
        }

        protected virtual void GenerateExists(ExistsNode exists, StringBuilder sb)
        {
            switch (exists.Type)
            {
                case ExistsNodeType.Exists:
                    {
                        sb.Append(" EXISTS ");
                    }
                    break;
                case ExistsNodeType.NotExists:
                    {
                        sb.Append(" NOT EXISTS ");
                    }
                    break;
            }
            GenerateSubSelect(exists.Query, sb);
        }

        protected virtual void GenerateCondition(ConditionNode condition, StringBuilder sb)
        {
            switch (condition.Type)
            {
                case ConditionNodeType.IsNull:
                    {
                        sb.Append(" IS NULL ");
                    }
                    break;
                case ConditionNodeType.IsNotNull:
                    {
                        sb.Append(" IS NOT NULL ");
                    }
                    break;
                case ConditionNodeType.Equals:
                    {
                        sb.Append(" = ");
                    }
                    break;
                case ConditionNodeType.NotEquals:
                    {
                        sb.Append(" <> ");
                    }
                    break;
                case ConditionNodeType.GreaterThan:
                    {
                        sb.Append(" > ");
                    }
                    break;
                case ConditionNodeType.GreaterThanOrEqual:
                    {
                        sb.Append(" >= ");
                    }
                    break;
                case ConditionNodeType.LessThan:
                    {
                        sb.Append(" < ");
                    }
                    break;
                case ConditionNodeType.LessThanOrEqual:
                    {
                        sb.Append(" <= ");
                    }
                    break;
                case ConditionNodeType.Like:
                    {
                        sb.Append(" LIKE ");
                    }
                    break;
                case ConditionNodeType.NotLike:
                    {
                        sb.Append(" NOT LIKE ");
                    }
                    break;
                case ConditionNodeType.In:
                    {
                        sb.Append(" IN ");
                    }
                    break;
                case ConditionNodeType.NotIn:
                    {
                        sb.Append(" NOT IN ");
                    }
                    break;
            }
        }

        protected virtual void GenerateConstant(object value, StringBuilder sb)
        {
            if (value is bool)
            {
                if ((bool)value)
                {
                    sb.Append("1");
                }
                else
                {
                    sb.Append("0");
                }
            }
            else if (value is Guid)
            {
                sb.Append("'");
                sb.Append(value.ToString());
                sb.Append("'");
            }
            else if (value is DateTime)
            {
                sb.Append("'");
                sb.Append(((DateTime)value).ToString());
                sb.Append("'");
            }
            else if (value is string)
            {
                sb.Append("'");
                sb.Append(((string)value).Replace("'", "''"));
                sb.Append("'");
            }
            else if (value == null)
            {
                sb.Append("null");
            }
            else
            {
                sb.Append(value.ToString());
            }
        }

        protected virtual void GenerateAggregate(string clause, StringBuilder sb)
        {
            sb.Append("(");
            sb.Append(clause);
            sb.Append(")");
        }

        protected virtual void GenerateParameter(object value, StringBuilder sb, Dictionary<string, DbParameter> parameters)
        {
            int num = parameters.Keys.Count;
            string key = "p" + num;
            parameters[key] = DataAccess.Instance.CreateParameter(key, value);

            sb.Append(ParameterToken + key);
        }

        protected virtual void GenerateSubSelect(Action<SelectQuery> query, StringBuilder sb)
        {
            sb.Append("(");
            var tmp = new SelectQuery();
            query(tmp);
            GenerateSelect(tmp, sb);
            sb.Append(")");
        }

        protected virtual void GenerateSelect(SelectQuery query, StringBuilder sb)
        {
            throw new NotImplementedException();
        }

        protected virtual void GenerateColumnName(string column, StringBuilder sb)
        {
            sb.Append(column);
        }

        protected virtual void GenerateAliasName(string alias, StringBuilder sb)
        {
            sb.Append("'");
            sb.Append(alias);
            sb.Append("'");
        }

        protected virtual void GenerateTableName(Table table, StringBuilder sb)
        {
            sb.Append(StartingQuoteToken);
            sb.Append(table.Name);
            sb.Append(EndingQuoteToken);
            if (!string.IsNullOrEmpty(table.Alias))
            {
                sb.Append(" AS ");
                sb.Append(StartingQuoteToken);
                sb.Append(table.Alias);
                sb.Append(EndingQuoteToken);
            }
        }
    }
}
